#include <iostream>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sstream>

#include <BaseException.h>
#include <ColaMensaje.h>

#define MSGLEN 100

using namespace std;

int calcularRandom ();


typedef struct msgColaTest {
	long mtype;
	char msg[MSGLEN];
	size_t msgSize;
} TMsgColaTest;


int main (int argc, char* argv[])
{
	int returnCode = 0;
	try
	{
		string nombreCola = "/tmp/testColaMensaje";
		int cantCiclos = 3;
		int cantHijos = 2;
		int numHijo = 0;
		int j = 0;
		pid_t pid = 1;
		
		ColaMensaje<TMsgColaTest> colaMsgPadre;
		colaMsgPadre.crear(nombreCola, CreationMode::NO_DEBE_EXISTIR);
		
		for( ; j < cantHijos; j++)
		{
			// El padre lanza la cantidad de hijos necesarios
			pid = fork ();
			
			numHijo++;
			if ( pid == 0 )
			{
				// Los hijos salen del loop
				break;
			}
		}
		
		if ( pid == 0 )
		{
			pid_t pidHijo = getpid();
			cout << "HIJO " << pidHijo << ": Intento abrir la cola de mensajes de mi padre " << nombreCola << endl;
			ColaMensaje<TMsgColaTest> colaMsgHijo(nombreCola, CreationMode::DEBE_EXISTIR);
			cout << "HIJO " << pidHijo << ": Cola de mensajes de mi padre abierta" << endl;
			
			TMsgColaTest msg;
			msg.mtype = numHijo;
			
			srand ( time(NULL) );
			
			int i = 0;
			for( ; i < cantCiclos; i++)
			{
				cout << "HIJO " << pidHijo << ": Ciclo numero " << i + 1 << endl;
				
				stringstream mensaje;
				mensaje << "Hola pa. Soy " << numHijo << ". Este es el " << i + 1 << " mensaje que te dejo";
				
				string mensajeStr = mensaje.str();
				msg.msgSize=mensajeStr.size();
				
				if(msg.msgSize > MSGLEN)
					mensajeStr.resize(MSGLEN);
				mensajeStr.copy(msg.msg, msg.msgSize);
				
				cout << "HIJO " << pidHijo << ": Escribo el mensaje:" << mensaje.str() << endl;
				colaMsgHijo.escribir(msg);
			}
			
			cout << "HIJO " << pidHijo << ": Destruyo la instancia pero no elimino la cola de mensajes" << endl;
			colaMsgHijo.destruir();
			
			cout << "HIJO " << pidHijo << ": Cola de mensajes destruida. Finalizo" << endl;
			return returnCode;
		}
		else 
		{
			cout << "PADRE: PID:" << getpid() << endl;
			cout << "PADRE: Espero 3 segundos a que mis hijos me dejen mensajes" << endl;
			sleep(3);
			
			cout << "PADRE: Voy a leer mensajes de la cola " << nombreCola 
			<< " priorizando por los numeros de hijo descendentemente" << endl;
			int i, j;
			for( i = 0; i < cantCiclos; i++)
			{
				cout << "PADRE: Ciclo " << i + 1 << endl;
				for( j = cantHijos; j > 0; j--)
				{
					cout << "PADRE: Obtengo mensaje " << i+1 << " de hijo " << j << endl;
					TMsgColaTest msgRcv;
					colaMsgPadre.leer(j,&msgRcv);
					string mensajeStr(msgRcv.msg, msgRcv.msgSize);
					cout << "PADRE: Mensaje de mi hijo:" << mensajeStr << endl;
				}
			}
			
			cout << "PADRE: Espero a que mis hijos finalicen" << endl;
			int estado;
			while( wait( (void*) &estado) > 0);
			
			cout << "PADRE: Mis hijos finalizaron. Libero recursos compartidos." << endl;
			
			colaMsgPadre.eliminar();
			
			cout << "PADRE: Finalizo." << endl;
		}
		std::cout << "testColaMensajes OK" << std::endl;
	}
	catch (const BaseException& e)
	{
		std::cerr << "testColaMensajes FAIL: Error " << e.getCode() << ":" << e.what() << std::endl;
		returnCode = e.getCode();
	}
	return returnCode;
}


int calcularRandom () {
	int resultado = rand() % 100 + 1;
	return resultado;
}
